package com.demandbreakdown.xiyun.strategy;

import cn.hutool.core.util.StrUtil;
import com.demandbreakdown.xiyun.common.base.ResultCode;
import com.demandbreakdown.xiyun.common.exception.BusinessException;
import com.demandbreakdown.xiyun.config.CosConfig;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.model.*;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import static com.demandbreakdown.xiyun.common.constant.FileConstant.*;

/**
 * 腾讯云COS存储策略实现
 * 负责与腾讯云COS服务交互的所有技术操作
 *
 * @author poxz
 */
@Component
@ConditionalOnProperty(name = "storage.type", havingValue = "cos")
@Slf4j
@RequiredArgsConstructor
public class CosStrategy implements StorageStrategy {

    private final COSClient cosClient;
    private final CosConfig cosConfig;

    @Override
    public String upload(InputStream inputStream, String filePath, String contentType) {
        try {
            log.debug("COS上传开始: bucket={}, filePath={}", cosConfig.getBucket(), filePath);

            // 创建文件元数据
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(contentType);
            metadata.setCacheControl(CACHE_CONTROL_ONE_YEAR);

            // 创建上传请求
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    cosConfig.getBucket(),
                    filePath,
                    inputStream,
                    metadata
            );

            // 执行上传
            PutObjectResult result = cosClient.putObject(putObjectRequest);

            // 生成文件访问URL
            String fileUrl = cosConfig.getHost() + "/" + filePath;

            log.info("COS上传成功: filePath={}, etag={}", filePath, result.getETag());
            return fileUrl;

        } catch (CosServiceException e) {
            log.error("COS服务异常: StatusCode={}, ErrorCode={}, Message={}",
                    e.getStatusCode(), e.getErrorCode(), e.getMessage());
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "文件上传失败");
        } catch (CosClientException e) {
            log.error("COS客户端异常: {}", e.getMessage(), e);
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "文件上传失败");
        } catch (Exception e) {
            log.error("文件上传异常: filePath={}", filePath, e);
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "文件上传失败");
        }
    }

    @Override
    public void delete(String filePath) {
        try {
            log.debug("COS删除文件: bucket={}, filePath={}", cosConfig.getBucket(), filePath);

            cosClient.deleteObject(cosConfig.getBucket(), filePath);

            log.info("COS删除成功: filePath={}", filePath);

        } catch (CosServiceException e) {
            log.error("COS删除服务异常: StatusCode={}, ErrorCode={}, Message={}",
                    e.getStatusCode(), e.getErrorCode(), e.getMessage());
        } catch (CosClientException e) {
            log.error("COS删除客户端异常: {}", e.getMessage());
        } catch (Exception e) {
            log.error("文件删除异常: filePath={}", filePath, e);
        }
    }

    @Override
    public boolean exists(String filePath) {
        try {
            log.debug("COS检查文件存在性: bucket={}, filePath={}", cosConfig.getBucket(), filePath);

            cosClient.getObjectMetadata(cosConfig.getBucket(), filePath);
            return true;

        } catch (CosServiceException e) {
            if (e.getStatusCode() == HTTP_STATUS_NOT_FOUND) {
                return false;
            }
            log.error("COS检查文件存在性异常: StatusCode={}, Message={}",
                    e.getStatusCode(), e.getMessage());
            return false;
        } catch (Exception e) {
            log.error("检查文件存在性异常: filePath={}", filePath, e);
            return false;
        }
    }

    @Override
    public void generateDownloadUrl(String fileUrl, String fileName, HttpServletResponse response) {
        try {
            // 从URL提取文件路径
            String filePath = extractFilePathFromUrl(fileUrl);
            if (StrUtil.isBlank(filePath)) {
                throw new BusinessException(ResultCode.PARAMS_ERROR, "无效的文件URL");
            }

            log.debug("COS生成下载链接: filePath={}, fileName={}", filePath, fileName);

            // 检查文件是否存在
            if (!exists(filePath)) {
                throw new BusinessException(ResultCode.NOT_FOUND, "文件不存在");
            }

            // 生成预签名下载URL
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(
                    cosConfig.getBucket(),
                    filePath,
                    HttpMethodName.GET
            );

            // 设置过期时间
            request.setExpiration(new java.util.Date(System.currentTimeMillis() + DOWNLOAD_URL_EXPIRE_MS));

            // 设置下载文件名
            ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
            responseHeaders.setContentDisposition("attachment; filename*=UTF-8''" + encodedFileName);
            request.setResponseHeaders(responseHeaders);

            // 生成下载URL
            URL downloadUrl = cosClient.generatePresignedUrl(request);

            // 重定向到下载链接
            response.sendRedirect(downloadUrl.toString());

            log.info("COS下载链接生成成功: filePath={}, fileName={}", filePath, fileName);

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("生成下载链接失败: fileUrl={}, fileName={}", fileUrl, fileName, e);
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "生成下载链接失败");
        }
    }

    @Override
    public String getStrategyName() {
        return "TencentCOS";
    }

    /**
     * 从URL提取文件路径
     *
     * @param fileUrl 文件完整URL
     * @return 文件相对路径
     */
    private String extractFilePathFromUrl(String fileUrl) {
        if (StrUtil.isBlank(fileUrl)) {
            return null;
        }

        // URL格式: https://xxx.cos.ap-chengdu.myqcloud.com/pictures/123/456/uuid.jpg
        // 提取: pictures/123/456/uuid.jpg

        String host = cosConfig.getHost();
        if (fileUrl.startsWith(host)) {
            return fileUrl.substring(host.length() + 1);
        }

        // 如果URL不匹配配置的host，尝试提取路径部分
        int pathStart = fileUrl.indexOf('/', HTTPS_PROTOCOL_PREFIX_LENGTH);
        if (pathStart > 0) {
            return fileUrl.substring(pathStart + 1);
        }

        return null;
    }
}
